//
//  BLETask.m
//  BLESDK-BLESDK
//
//  Created by 李阳 on 2018/8/29.
//

#import "BLESession.h"

#import "BLEDevice.h"
#import "BLERequest.h"
#import "NSError+BLEAdd.h"
#import "NSArray+BLEAdd.h"

@interface BLESession ()

@property (nonatomic, assign) dispatch_semaphore_t semaphore;

/// 代理
@property (nonatomic, weak) id <BLESessionTaskDelegate> delgate;

@property (nonatomic, strong) NSThread *mediaThread;
@property (nonatomic, strong) NSThread *mainThread;


@property (nonatomic, strong) NSMutableArray *normalTasks;
@property (nonatomic, strong) NSMutableArray *mediaTasks;
@property (nonatomic, strong) NSMutableArray *contactTasks;

- (void)lock;
- (void)unlock;

/// 正在执行的普通蓝牙任务
@property (nonatomic, strong) BLETask *runningNormalTask;
/// 正在执行的媒体蓝牙任务
@property (nonatomic, strong) BLETask *runningMedialTask;
/// 正在执行的联系人蓝牙任务
@property (nonatomic, strong) BLETask *runningContactTask;

@end

@interface BLETask ()

/// 任务状态
@property (nonatomic, assign) BLETaskState state;
/// 错误
@property (nonatomic, strong) NSError *error;
@property (nonatomic, weak) BLESession *session;

/// 定时器
@property (nonatomic, strong) NSTimer *timer;

- (instancetype)initWithRequest:(BLERequest *)request;

@end

@implementation BLESession

- (BLENormalTask *)normalTaskWithReuest:(BLERequest *)request
{
    BLENormalTask *task = [[BLENormalTask alloc]initWithRequest:request];
    task.session = self;
    return task;
}
- (BLEMediaTask *)mediaTaskWithReuest:(BLERequest *)request
{
    BLEMediaTask *task = [[BLEMediaTask alloc]initWithRequest:request];
    task.session = self;
    return task;
}
- (BLEContactTask *)contactTaskWithReuest:(BLERequest *)request
{
    BLEContactTask *task = [[BLEContactTask alloc]initWithRequest:request];
    task.session = self;
    return task;
}

- (void)beginNormalTasks
{
    [self performSelector:@selector(scheduledNormalTasks) onThread:self.mainThread withObject:nil waitUntilDone:NO modes:@[NSRunLoopCommonModes]];
}
- (void)scheduledNormalTasks
{
    if (self.runningNormalTask &&
        self.runningNormalTask.state == BLETaskStateRunning)
    {
        return;
    }
    
    BLENormalTask *task = [self retrieveNormalTask];
    self.runningNormalTask = task;
    if (task)
    {
        [task resume];
    }
}

- (void)beginMediaTasks
{
    [self performSelector:@selector(scheduledMediaTasks) onThread:self.mediaThread withObject:nil waitUntilDone:NO modes:@[NSRunLoopCommonModes]];
}
- (void)scheduledMediaTasks
{
    if (self.runningMedialTask &&
        self.runningMedialTask.state == BLETaskStateRunning)
    {
        return;
    }
    
    BLEMediaTask *task = [self retrieveMediaTask];
    self.runningMedialTask = task;
    if (task)
    {
        [task resume];
    }
}
- (void)beginContactTasks
{
    [self performSelector:@selector(scheduledContactTasks) onThread:self.mediaThread withObject:nil waitUntilDone:NO modes:@[NSRunLoopCommonModes]];
}
- (void)scheduledContactTasks
{
    if (self.runningContactTask &&
        self.runningContactTask.state == BLETaskStateRunning)
    {
        return;
    }
    
    BLEContactTask *task = [self retrieveContactTask];
    self.runningNormalTask = task;
    if (task)
    {
        [task resume];
    }
}

#pragma mark NSObject

- (instancetype)initWithDelegate:(id<BLESessionDelegate>)delegate
{
    self = [super init];
    if (!self)
    {
        return nil;
    }
    
    self.delgate = delegate;
    
    return self;
}


#pragma mark - Unitls

- (void)removeNormaltask:(BLENormalTask *)task
{
    [self lock];
    [self.normalTasks removeObject:task];
    [self unlock];
}

- (BLENormalTask *)retrieveNormalTask
{
    BLENormalTask *task = nil;
    [self lock];
    task = self.normalTasks.firstObject;
    [self unlock];
    return task;
}
- (BLEMediaTask *)retrieveMediaTask
{
    BLEMediaTask *task = nil;
    [self lock];
    task = self.mediaTasks.firstObject;
    [self unlock];
    return task;
}
- (BLEContactTask *)retrieveContactTask
{
    BLEContactTask *task = nil;
    [self lock];
    task = self.contactTasks.firstObject;
    [self unlock];
    return task;
}

- (void)addNormalTasks:(BLENormalTask *)task
{
    [self lock];
    if (![self.normalTasks containsObject:task])
    {
        if (task.priority == BLETaskPriorityHigh)
        {
            [self.normalTasks insertObject:task atIndex:0];
        }
        else
        {
            [self.normalTasks addObject:task];
        }
    }
    [self unlock];
}
- (void)addMediaTasks:(BLEMediaTask *)task
{
    [self lock];
    if (![self.mediaTasks containsObject:task])
    {
        if (task.priority == BLETaskPriorityHigh)
        {
            [self.mediaTasks insertObject:task atIndex:0];
        }
        else
        {
            [self.mediaTasks addObject:task];
        }
    }
    [self unlock];
}
- (void)addContactTasks:(BLEContactTask *)task
{
    [self lock];
    if (![self.contactTasks containsObject:task])
    {
        if (task.priority == BLETaskPriorityHigh)
        {
            [self.contactTasks insertObject:task atIndex:0];
        }
        else
        {
            [self.contactTasks addObject:task];
        }
    }
    [self unlock];
}

- (void)lock
{
    dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
}
- (void)unlock
{
    dispatch_semaphore_signal(self.semaphore);
}


- (void)mediaThreadEnteryPoint
{
    @autoreleasepool
    {
        [[NSThread currentThread] setName:@"BLESDK.mediaThread"];
        
        //添加端口，防止runloop直接退出
        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
        [runLoop run];
    }
}

- (void)mainThreadEnteryPoint
{
    @autoreleasepool
    {
        [[NSThread currentThread] setName:@"BLESDK.mainThread"];
        
        //添加端口，防止runloop直接退出
        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
        [runLoop run];
    }
}

#pragma mark - Getter & Setter


- (NSThread *)mediaThread
{
    if (_mediaThread) return _mediaThread;
    _mediaThread = [[NSThread alloc]initWithTarget:self selector:@selector(mediaThreadEnteryPoint) object:nil];
    [_mediaThread start];
    return _mediaThread;
}


- (NSThread *)mainThread
{
    if (_mainThread) return _mainThread;
    _mainThread = [[NSThread alloc]initWithTarget:self selector:@selector(mainThreadEnteryPoint) object:nil];
    [_mainThread start];
    return _mainThread;
}


- (NSMutableArray *)normalTasks
{
    if (_normalTasks) return _normalTasks;
    _normalTasks = [NSMutableArray array];
    return _normalTasks;
}
- (NSMutableArray *)mediaTasks
{
    if (_mediaTasks) return _mediaTasks;
    _mediaTasks = [NSMutableArray array];
    return _mediaTasks;
}
- (NSMutableArray *)contactTasks
{
    if (_contactTasks) return _contactTasks;
    _contactTasks = [NSMutableArray array];
    return _contactTasks;
}
- (dispatch_semaphore_t)semaphore
{
    if (_semaphore) return _semaphore;
    _semaphore = dispatch_semaphore_create(1);
    return _semaphore;
}

@end



@implementation BLETask

/// 取消
- (void)cancel
{
    
}
/// 挂起
- (void)suspend
{
    
}

/// 开始
- (void)resume
{
    self.state = BLETaskStateRunning;
    
    [self.session.delgate session:self.session
                       normalTask:self
                     beginRequest:self.request];
}


- (void)completeWithError:(NSError *)error
{
    self.error = error;
    self.state = BLETaskStateCompleted;
}

- (void)timeoutAction
{
    self.error = [NSError bleTimeoutError];
    self.state = BLETaskStateCompleted;
}

- (void)setState:(BLETaskState)state
{
    _state = state;
    
    if (state == BLETaskStateRunning)
    {
        _timer = [NSTimer timerWithTimeInterval:self.request.timeout
                                         target:self
                                       selector:@selector(timeoutAction)
                                       userInfo:nil
                                        repeats:NO];
        [[NSRunLoop currentRunLoop]addTimer:_timer forMode:NSRunLoopCommonModes];
    }
    
    if (state == BLETaskStateCompleted)
    {
        [_timer invalidate];
        _timer = nil;
        !self.completionBlock ?: self.completionBlock(self);
        [self.session removeNormaltask:self];
        [self resume];
    }
}

#pragma mark NSObject

- (instancetype)initWithRequest:(BLERequest *)request
{
    self = [super init];
    if (!self)
    {
        return nil;
    }
    
    self->_request = request;
    
    return self;
}

@end


@implementation BLENormalTask

@end

@implementation BLEMediaTask

@end

@implementation BLEContactTask

@end



